#!/usr/bin/python3

import os
import msvcrt
import openpyxl
from tqdm import tqdm
from datetime import datetime, timedelta

# 查找日志文件
log_file_name = ''
for filename in os.listdir('./'):
    if filename.split('.')[-1] == 'log':
        log_file_name = filename
        continue  # 只处理当前文件夹下的第一个log文件

if log_file_name == '':
    print('-----------------------------------------------------')
    print('警告：没有找到日志文件，请确保将\'.log\'放入了当前文件夹')
    print('-----------------------------------------------------')
    print("按下任意键以退出程序...")
    msvcrt.getch()

# 打开日志文件
print('找到日志文件：' + log_file_name)
print('开始读取并解析日志文件...')
log_file = open(log_file_name, encoding='utf8')

# 创建参数文件
param_file_name = log_file_name.split('.log')[0] + '.param'
param_file = open(param_file_name, 'w')

# 创建Excel文件
workbook = openpyxl.Workbook()

# 输入：GPS周、GPS周内秒
# 输出：北京时间
def gps_week_seconds_to_beijing_time(gpsweek, gpsseconds):
    datetimeformat = "%Y-%m-%d %H:%M:%S.%f"
    epoch = datetime.strptime("1980-01-06 00:00:00.000", datetimeformat)
    elapsed = timedelta(days=(gpsweek*7), seconds=(gpsseconds-18))
    return datetime.strftime(epoch+elapsed+timedelta(hours=8), datetimeformat)

# 读取日志文件
lines = log_file.readlines()

# 查找GPS时间信息
GotFirstGPSTime = False
FirstGPSgwk = 0
FirstGPSgms = 0
timedelta_GPS2FMU = 0
for line in lines:
    if line.split(', ')[0] == 'GPS':
        if int(line.split(', ')[3]) >= 3:  # GPS已经定位
            GotFirstGPSTime = True
            FirstGPSgms = float(line.split(', ')[4]) / 1000.0
            FirstGPSgwk = int(line.split(', ')[5])
            fmu_time = float(line.split(', ')[1]) / 1000000.0
            timedelta_GPS2FMU = FirstGPSgms - fmu_time
            break

# 解析信息
for line in tqdm(lines):
    line_head = line.split(', ')[0]  # 提取本行的起始字符
    if line_head == 'FMT':  # 日志格式说明（“FMT”应该是“format”的简称）
        sheet_title = line.split(', ')[3] 
        sheet = workbook.create_sheet(title=sheet_title)
        sheet.append(line.split(', ')[5].split(','))
        sheet_format = line.split(', ')[4]  # 数据类型字段
        sheet_format_list = []
        for c in sheet_format:  # 此处参考APM源代码"libraries/AP_Logger/LogStructure.h"顶部注释
            if c == 'a':
                sheet_format_list.append('int16_t[32]')
            elif c == 'b':
                sheet_format_list.append('int8_t')
            elif c == 'B':
                sheet_format_list.append('uint8_t')
            elif c == 'h':
                sheet_format_list.append('int16_t')
            elif c == 'H':
                sheet_format_list.append('uint16_t')
            elif c == 'i':
                sheet_format_list.append('int32_t')
            elif c == 'I':
                sheet_format_list.append('uint32_t')
            elif c == 'f':
                sheet_format_list.append('float')
            elif c == 'd':
                sheet_format_list.append('double')
            elif c == 'n':
                sheet_format_list.append('char[4]')
            elif c == 'N':
                sheet_format_list.append('char[16]')
            elif c == 'Z':
                sheet_format_list.append('char[64]')
            elif c == 'c':
                sheet_format_list.append('int16_t * 100')
            elif c == 'C':
                sheet_format_list.append('uint16_t * 100')
            elif c == 'e':
                sheet_format_list.append('int32_t * 100')
            elif c == 'E':
                sheet_format_list.append('uint32_t * 100')
            elif c == 'L':
                sheet_format_list.append('int32_t latitude/longitude')
            elif c == 'M':
                sheet_format_list.append('uint8_t flight mode')
            elif c == 'q':
                sheet_format_list.append('int64_t')
            elif c == 'Q':
                sheet_format_list.append('uint64_t')
            else:
                sheet_format_list.append('unknown')
        sheet.append(sheet_format_list)
    elif line_head == 'PARM':  #飞控参数
        if line.split(', ')[-2] == 'STAT_FLTTIME':
            continue
        if line.split(', ')[-2] == 'STAT_RUNTIME':
            continue
        param_file.write(line.split(', ', 2)[-1])
    else:
        sheet_name = line.split(', ')[0]
        if sheet_name not in workbook.sheetnames:
            continue
        if sheet_name == 'FILE':
            continue
        if sheet_name == 'MSG':
            data_num_formatted = []
            msg_time = int(line.split(', ')[1])
            data_num_formatted.append(msg_time)
            data_num_formatted.append(line.split(', ', 2)[2])
            workbook[sheet_name].append(data_num_formatted)
            continue
        if workbook[sheet_name]['B1'].value == 'I' or workbook[sheet_name]['B1'].value == 'Instance':  # 对于多实例的日志项，不同实例占用不同的sheet
            instance_num = line.split(', ')[2]
            template_sheet_name = sheet_name
            sheet_name = sheet_name + ' ' + instance_num
            if sheet_name not in workbook.sheetnames:
                sheet = workbook.create_sheet(title=sheet_name)
                # 将头两行复制过去
                selected_rows = workbook[template_sheet_name].iter_rows(min_row=1, max_row=2)
                copied_rows = [row for row in selected_rows]
                for row in copied_rows:
                    workbook[sheet_name].append([cell.value for cell in row])
        data_num_formatted = []
        data_column = 1
        for data in line.split(', ')[1:]:
            data_format = workbook[sheet_name].cell(row=2, column=data_column).value
            if data_format == 'int32_t latitude/longitude':
                data_num_formatted.append(float(data))
            elif ' * 100' in data_format:
                data_num_formatted.append(float(data))
            elif data_format == 'int16_t[32]':
                data_num_formatted.append(data)
            elif data_format == 'uint8_t flight mode':
                data_num_formatted.append(data)
            elif 'int' in data_format:
                data_num_formatted.append(int(data))
            elif 'char' in data_format:
                data_num_formatted.append(data)
            elif data_format == 'unknown':
                data_num_formatted.append(data)
            else:
                data_num_formatted.append(float(data))
            data_column = data_column + 1
        workbook[sheet_name].append(data_num_formatted)

# 删除多余的sheet
unused_sheet_name_list = ['Sheet', 'FMT', 'UNIT', 'FMTU', 'MULT', 'PARM']
for sheet_name in unused_sheet_name_list:
    if sheet_name in workbook.sheetnames:
        workbook.remove(workbook[sheet_name])

# 删除无数据的sheet
for sheet_name in workbook.sheetnames:
    if workbook[sheet_name]['A3'].value == None:
        workbook.remove(workbook[sheet_name])

# 将sheet按照名字排序
workbook._sheets.sort(key=lambda ws: ws.title)

# 删除每个sheet中数据类型的行
for sheet_name in workbook.sheetnames:
    workbook[sheet_name].delete_rows(2)

# 添加日期和时间列
print('解析完成，开始将飞控时间转换为北京时间，这需要花一些时间...')
for sheet_name in workbook.sheetnames:
    workbook[sheet_name].insert_cols(1)
    workbook[sheet_name].cell(1, 1).value = 'DataTime'
    for row in range(2, workbook[sheet_name].max_row+1):
        FMUtime = workbook[sheet_name].cell(row, 2).value
        workbook[sheet_name].cell(row, 1).value = gps_week_seconds_to_beijing_time(FirstGPSgwk, timedelta_GPS2FMU + float(FMUtime) / 1000000.0)

# 关闭参数文件
param_file.close()

# 将参数文件内容排序
param_file = open(param_file_name, 'r')
param_lines = param_file.readlines()
param_file.close()
param_lines.sort()
param_file = open(param_file_name, 'w')
for line in param_lines: 
    param_file.write(line)
param_file.close()

# 关闭Excel文件
print('开始创建Excel文件，这需要花一些时间...')
workbook.save(log_file_name.split('.log')[0] + '.xlsx')

# 关闭日志文件
log_file.close()

print('运行成功，生成Excel文件：' + log_file_name.split('.log')[0] + '.xlsx')
print('-----------------------------------------------------')
print('怒飞垂云：怒而飞，其翼若垂天之云！http://www.nufeichuiyun.com/')
print('此软件问题反馈、无人机飞控软硬件开发，请联系QQ：3500985284')
print('-----------------------------------------------------')
print("按下任意键以退出程序...")
msvcrt.getch()
